#include "congresso.h"
#include <GL/gl.h>
#include "hemisphere.h"
#include "cube.h"
#include "rectangle.h"

Congresso::Congresso()
{
    Hemisphere *hemisferio_esquerdo = new Hemisphere();
    Hemisphere *hemisferio_direito = new Hemisphere();
    Rectangle *grama = new Rectangle(Point(-1.0, 0.0, -1.0), Point(-1.0, 0.0, 1.0), Point(1.0, 0.0, 1.0), Point(1.0, 0.0, -1.0));
    Cube *placa1 = new Cube();
    Cube *placa2 = new Cube();
    Cube *torre_esquerda = new Cube();
    Cube *torre_direita = new Cube();
    Cube *ponte = new Cube();
    Cube *inicio_rampa = new Cube();
    Cube *subida_rampa = new Cube();
    Cube *fim_rampa = new Cube();

    CgMaterial corgrama(CgColor(0.0, 0.4, 0.0), CgColor(0.0, 0.4, 0.0), CgColor(0.0, 0.0, 0.0));
    CgMaterial corconcreto(CgColor(0.2, 0.2, 0.2), CgColor(0.2, 0.2, 0.2), CgColor(0.0, 0.0, 0.0));

    hemisferio_esquerdo->multiplyCurrentTransformation(Matrix::xRotationMatrix(90.0));
    hemisferio_esquerdo->multiplyCurrentTransformation(Matrix::translationMatrix(-2.0, 1.5, 0.0));

    hemisferio_direito->multiplyCurrentTransformation(Matrix::xRotationMatrix(-90.0));
    hemisferio_direito->multiplyCurrentTransformation(Matrix::translationMatrix(2.0, 2.5, 0.0));

    grama->multiplyCurrentTransformation(Matrix::scalingMatrix(15.0, 0.0, 15.0));
    grama->set_material(corgrama);

    placa1->multiplyCurrentTransformation(Matrix::scalingMatrix(6.5, 0.2, 3.0));
    placa1->multiplyCurrentTransformation(Matrix::translationMatrix(0.0, 0.5, 0.0));
    placa1->set_material(corconcreto);

    placa2->multiplyCurrentTransformation(Matrix::scalingMatrix(6.5, 0.2, 3.0));
    placa2->multiplyCurrentTransformation(Matrix::translationMatrix(0.0, 1.5, 0.0));
    placa2->set_material(corconcreto);

    torre_esquerda->multiplyCurrentTransformation(Matrix::scalingMatrix(0.5, 5.0, 1.0));
    torre_esquerda->multiplyCurrentTransformation(Matrix::translationMatrix(-0.5, 4.0, 0.0));
    torre_esquerda->set_material(corconcreto);

    torre_direita->multiplyCurrentTransformation(Matrix::scalingMatrix(0.5, 5.0, 1.0));
    torre_direita->multiplyCurrentTransformation(Matrix::translationMatrix(0.5, 4.0, 0.0));
    torre_direita->set_material(corconcreto);

    ponte->multiplyCurrentTransformation(Matrix::translationMatrix(0.0, 4.0, 0.0));
    ponte->set_material(corconcreto);

    inicio_rampa->multiplyCurrentTransformation(Matrix::scalingMatrix(1.0, 0.1, 2.0));
    inicio_rampa->multiplyCurrentTransformation(Matrix::xRotationMatrix(30.0));
    inicio_rampa->multiplyCurrentTransformation(Matrix::translationMatrix(0.0, 0.0, 5.3));
    inicio_rampa->set_material(corconcreto);

    subida_rampa->multiplyCurrentTransformation(Matrix::scalingMatrix(0.5, 0.1, 2.0));
    subida_rampa->multiplyCurrentTransformation(Matrix::xRotationMatrix(26.6));
    subida_rampa->multiplyCurrentTransformation(Matrix::translationMatrix(-0.5, 1.2, 2.4));
    subida_rampa->set_material(corconcreto);

    fim_rampa->multiplyCurrentTransformation(Matrix::scalingMatrix(1.0, 0.1, 3.0));
    fim_rampa->multiplyCurrentTransformation(Matrix::translationMatrix(0.0, 0.5, 2.9));
    fim_rampa->set_material(corconcreto);

    components_.push_back(hemisferio_esquerdo);
    components_.push_back(hemisferio_direito);
    components_.push_back(grama);
    components_.push_back(placa1);
    components_.push_back(placa2);
    components_.push_back(torre_esquerda);
    components_.push_back(torre_direita);
    components_.push_back(ponte);
    components_.push_back(inicio_rampa);
    components_.push_back(subida_rampa);
    components_.push_back(fim_rampa);
}

Congresso::~Congresso()
{
    std::vector<ICgObject*>::iterator it;
    for(it = components_.begin() ; it != components_.end() ; it++) {
        delete *it;
    }
}

bool Congresso::intersect(const Ray &r, double &t, Vector &normal) const
{
    double temp_t = 0.0;
    Vector temp_normal;
    std::vector<ICgObject*>::const_iterator it;

    t = -1.0;
    for(it = components_.begin() ; it != components_.end() ; it++) {
        ICgObject *obj = *it;
        if( obj->intersect(r, temp_t, temp_normal) && (t < 0.0 || temp_t < t)) {
            t = temp_t;
            normal = temp_normal;
        }
    }

    return t > 0.0;
}

void Congresso::openGlRender() const
{
    double tr[16];
    for(size_t i = 0 ; i < components_.size() ; i++) {
        ICgObject *obj = components_[i];
        glPushMatrix();
        obj->transformation().toOpenGLMatrix(tr);
        glMultMatrixd(tr);
        obj->openGlRender();
        glPopMatrix();
    }
}
